package com.juyu.miliao.api.service;

import com.juyu.miliao.api.cache.RobotMessageCache;
import com.juyu.miliao.api.constant.UserHostConstant;
import com.juyu.miliao.api.dao.mysql.MatchHostDao;
import com.juyu.miliao.api.dao.mysql.RegisterAddressDao;
import com.juyu.miliao.api.dao.mysql.UserInfoDao;
import com.juyu.miliao.api.dao.redis.LineTimeRedisDao;
import com.juyu.miliao.api.domain.Appkey;
import com.juyu.miliao.api.domain.RegisterAddress;
import com.juyu.miliao.api.domain.RobotMessage;
import com.juyu.miliao.api.domain.User;
import com.juyu.miliao.api.util.RedisKeys;
import com.juyu.miliao.common.netease.NetEaseCloudUserService;
import com.juyu.miliao.common.util.CommonUtil;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import static com.juyu.miliao.api.constant.UserHostConstant.SAME_HOST;
import static com.juyu.miliao.api.constant.UserHostConstant.SAME_ONLINE_HOST;

/**
 * @author jh
 * 2018/10/9
 */
@Service
@Slf4j
public class MatchHostService {

    @Resource
    private MatchHostDao matchHostDao;

    @Resource
    private UserInfoDao userInfoDao;

    @Resource
    private RegisterAddressDao registerAddressDao;

    @Resource
    private LineTimeRedisDao lineTimeRedisDao;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private AppKeyService appKeyService;

    public List<String> getRandomHostIcons() {
        int max = 6;
        List<String> list = matchHostDao.getMatchHostIcons(max);
        int size = list.size() > max ? max : list.size();
        return list.subList(0, size);
    }

    public void send(Long userId) {
        //获取用户地址
        RegisterAddress registerAddress = registerAddressDao.getRegisterAddressByUserId(userId);
        String city = null;
        if (registerAddress != null) {
            city = registerAddress.getCity();
        }
        Map<Long, String> map = getMatchHostIds(userId, city);
        //发消息
        sendMsg(userId, map, city);
    }

    public Map<Long, String> getMatchHostIds(Long userId, String city) {
        Map<Long, String> map = new HashMap<>(8);
        if (StringUtils.isNotEmpty(city)) {
            city = city.replaceAll("市", "");
            //同城2个 排除男主播
            List<Long> sameUserIds = userInfoDao.getSameCityUser(city);
            if (!sameUserIds.isEmpty()) {
                //存在同城
                int length = sameUserIds.size();

                //2个之内 直接遍历
                if (length <= 2) {
                    for (Long i : sameUserIds) {
                        Boolean flag = lineTimeRedisDao.isMember(String.valueOf(i));
                        if (flag) {
                            map.put(i, city);
                        }
                    }
                } else {
                    //2个之外 存redis取交集
                    String[] toBeStored = new String[length];
                    for (int i = 0; i < length; i++) {
                        toBeStored[i] = String.valueOf(sameUserIds.get(i));
                    }

                    //随机取判断在线
                    stringRedisTemplate.opsForSet().add(SAME_HOST + userId, toBeStored);
                    stringRedisTemplate.expire(SAME_HOST + userId, 10, TimeUnit.MINUTES);
                    //取交集
                    Long saveNum = stringRedisTemplate.opsForSet().intersectAndStore(RedisKeys.SET_HOSTLINE.getValue(),
                            SAME_HOST + userId,
                            SAME_ONLINE_HOST + userId);
                    List<String> list = stringRedisTemplate.opsForSet().pop(SAME_ONLINE_HOST + userId, 2);
                    if (list != null && !list.isEmpty()) {
                        for (String s : list) {
                            map.put(CommonUtil.null2Long(s), city);
                        }
                    }
                    //删除set  大Key可能会有问题
                    stringRedisTemplate.delete(SAME_ONLINE_HOST + userId);
                    stringRedisTemplate.delete(SAME_HOST + userId);
                }
            }
        }

        //同城在线不够取只在线
        if (map.size() < 2) {
            int less = 2 - map.size();
            //这里取2倍,防止重复   这个random方法当set.size<count 时,返回整个set
            Long allCount = stringRedisTemplate.opsForSet().size(RedisKeys.SET_HOSTLINE.getValue());
            if (allCount != null && allCount != 0 && less * 2 >= allCount) {
                Set<String> set = stringRedisTemplate.opsForSet().members(RedisKeys.SET_HOSTLINE.getValue());
                if (set != null) {
                    for (String s : set) {
                        if (map.size() < 2 && !map.containsKey(CommonUtil.null2Long(s))) {
                            //过滤男主播
                            if (!userInfoDao.getUserSex(CommonUtil.null2Long(s))) {
                                continue;
                            }
                            map.put(CommonUtil.null2Long(s), null);
                        }
                    }
                }
            } else {
                List<String> list = stringRedisTemplate.opsForSet().randomMembers(RedisKeys.SET_HOSTLINE.getValue(), less * 2);
                if (CommonUtil.isNotEmptyCollection(list)) {
                    for (String s : list) {
                        if (map.size() < 2) {
                            if (!map.containsKey(CommonUtil.null2Long(s))) {
                                //过滤男主播
                                if (!userInfoDao.getUserSex(CommonUtil.null2Long(s))) {
                                    continue;
                                }
                                map.put(CommonUtil.null2Long(s), null);
                            }
                        }
                    }
                }
            }
        }

        //再加1个推荐的
        Long size = stringRedisTemplate.opsForZSet().zCard(UserHostConstant.HIGH_QUALITY);
        if (size != null && size != 0) {
            //主播不可能超过int  这不是完全随机,分4个以下就全遍历,4个以上就随机,不可能用递归,时间无法保证
            int intSize = CommonUtil.null2Int(size);
            if (intSize <= 4) {
                Set<String> set = stringRedisTemplate.opsForSet().members(UserHostConstant.HIGH_QUALITY);
                if (set != null) {
                    for (String s : set) {
                        if (!map.containsKey(CommonUtil.null2Long(s))) {
                            //过滤男主播
                            if (!userInfoDao.getUserSex(CommonUtil.null2Long(s))) {
                                continue;
                            }
                            map.put(CommonUtil.null2Long(s), null);
                            break;
                        }
                    }
                }
            } else {
                Random random = new Random();
                int range = random.nextInt(intSize - 4);
                Set<String> set = stringRedisTemplate.opsForZSet().range(UserHostConstant.HIGH_QUALITY, range, range + 4);
                if (CommonUtil.isNotEmptyCollection(set)) {
                    for (String s : set) {
                        if (!map.containsKey(CommonUtil.null2Long(s))) {
                            //过滤男主播
                            if (!userInfoDao.getUserSex(CommonUtil.null2Long(s))) {
                                continue;
                            }
                            map.put(CommonUtil.null2Long(s), null);
                            break;
                        }
                    }
                }
            }
        }

        //都不够随机取
        if (map.size() < 3) {
            int less = 3 - map.size();
            Set<Long> matchUserIds = new HashSet<>();
            if (!map.isEmpty()) {
                matchUserIds = map.keySet();
            }
            List<Long> randomUser = userInfoDao.getRandomHostUser(matchUserIds, less);
            //分库不能按顺序取
            int randomSize = randomUser.size();
            for (int i = 0; i < randomSize; i++) {
                int randomIndex = new Random().nextInt(randomUser.size());
                Long randomUserId = randomUser.get(randomIndex);
                map.put(randomUserId, null);
                randomUser.remove(randomIndex);
                if (map.size() >= 3) {
                    break;
                }
            }

        }

        return map;
    }

    public void sendMsg(Long userId, Map<Long, String> matchMap, String city) {
        String firstMsg = "";
        if (CommonUtil.isNotEmptyString(city)) {
            User user = userInfoDao.getUserInfoById(userId);
            int sex = user.getSex();
            //小哥哥,我也是杭州的,一起聊聊嘛
            String named = sex == 1 ? "小哥哥" : "小姐姐";
            firstMsg = new StringBuilder(named).append(",我也是").append(city).append("的,一起聊聊嘛").toString();
        }

        List<RobotMessage> textList = RobotMessageCache.INSTANCE.getRobotMessageList(1,1);
        List<RobotMessage> picList = RobotMessageCache.INSTANCE.getRobotMessageList(2,1);
        if (matchMap != null) {
            try {
                String temp = "";
                int i = 0;
                //主播给用户发消息,不保存记录 共3条
                for (Map.Entry<Long, String> entry : matchMap.entrySet()) {
                    //第1条,和位置相关
                    if (i == 0 && !firstMsg.isEmpty()) {
                        sendNetEaseMsg(userId, entry.getKey(), firstMsg);
                    } else if (i == 0 && textList != null) {
                        RobotMessage rm = textList.get((int) (Math.random() * textList.size()));
                        sendNetEaseMsg(userId, entry.getKey(), rm.getMessage());
                    } else if (i == 0 && picList != null) {
                        RobotMessage rm = picList.get((int) (Math.random() * picList.size()));
                        JSONObject body = new JSONObject();
                        body.put("msg", rm);
                        NetEaseCloudUserService.getSendMsg(userId, entry.getKey(), 1, body.toString(), "","");
                    }

                    //2 随机消息
                    if (i == 1 && textList != null) {
                        RobotMessage rm = textList.get((int) (Math.random() * textList.size()));
                        sendNetEaseMsg(userId, entry.getKey(), rm.getMessage());
                    } else if (i == 1 && picList != null) {
                        RobotMessage rm = picList.get((int) (Math.random() * picList.size()));
                        sendPicMsg(userId, entry.getKey(), rm);
                    }

                    //3图片
                    if (i == 2 && picList != null) {
                        RobotMessage rm = picList.get((int) (Math.random() * picList.size()));
                        sendPicMsg(userId, entry.getKey(), rm);
                    } else if (i == 2 && textList != null) {
                        RobotMessage rm = textList.get((int) (Math.random() * textList.size()));
                        sendNetEaseMsg(userId, entry.getKey(), rm.getMessage());
                    }
                    i++;
                }
            } catch (IOException e) {
                log.error("匹配页面发消息:errorMsg:{}", e.getMessage());
            }
        }
    }

    private void sendNetEaseMsg(long userId, long toUserId, String msg) throws IOException {
        JSONObject body = new JSONObject();
        body.put("msg", msg);
        String temp = NetEaseCloudUserService.getSendMsg(userId, toUserId, 0, body.toString(), "","");
    }

    private void sendPicMsg(Long userId, long hostUserId, RobotMessage pic) {

        JSONObject body = new JSONObject();
        body.put("name", System.currentTimeMillis());// 图片name

        try {
            URL url = new URL(pic.getMessage());
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            InputStream in = conn.getInputStream();
            BufferedImage sourceImg = ImageIO.read(in);
            int w = sourceImg.getWidth();
            int h = sourceImg.getHeight();
            body.put("md5", DigestUtils.md5Hex(in));// 图片文件md5
            body.put("url", pic.getMessage());
            String[] temp = pic.getMessage().split("\\.");
            body.put("ext", temp[temp.length - 1]);
            body.put("w", w);
            body.put("h", h);
            // 根据响应获取文件大小
            body.put("size", conn.getContentLength());
        } catch (Exception e) {
            log.error("发送图片消息异常-md5转换错误：userId={},error={}", userId, e);
        }

        //开发者扩展字段
        JSONObject ext = new JSONObject();
        //ext开发者扩展字段-type类型：1文字，2免费图片，3付费图片，4视频
        //imagetype 1：免费 2：付费
        ext.put("imagetype", 1);

        try {
            String temp = NetEaseCloudUserService.getSendMsg(userId, hostUserId, 1, body.toString(), ext.toString(),"");
            if (!temp.substring(temp.indexOf("code") + 6, temp.indexOf("code") + 9).equals("200")) {
                log.error("发送图片消息异常-云信：userId={},message={}", userId, temp);
            }
        } catch (Exception e) {
            log.error("发送图片消息异常：userId={},error={}", userId, e);
        }
    }

    public JSONObject getRandomHostUser() {
        Appkey appkey = appKeyService.getAppKeyByKey("newHostIdOpenApi");
        String[] array = appkey.getValue().split(",");
        String userId = array[(int)(Math.random() * array.length)];
        User user = userInfoDao.getUserInfoById(Long.parseLong(userId));
        JSONObject json = new JSONObject();
        json.put("userId",user.getUserId());
        json.put("nickName",user.getNickName());
        json.put("icon",user.getIcon());
        return json;
    }
}
